from flask import Flask, request, jsonify
from flask_cors import CORS
import process_api
import structs
import os 


app = Flask(__name__)

# 显式配置CORS，允许来自 http://localhost:3000 的请求，并明确允许常用方法和头
# 如果还报错CORS,看看后端是不是没跑起来
CORS(app,
     resources={r"/api/*": {"origins": "http://localhost:3000"}},
     supports_credentials=True,
     methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],  # 明确允许的方法
     allow_headers=["Content-Type", "Authorization"]  # 明确允许的请求头
)

##迎新第一步
@app.route('/api/lang', methods=['POST'])
def get_lang_direction():
    """生成并保存计划"""
    try:
        data = request.json
        lang = data.get('lang')
        direction = data.get('方向') # 保留'方向'以兼容当前前端

        if not lang:
            return jsonify({"error": "缺少 'lang' 参数"}), 400
        # 方向可以为空

        userId = data.get('userId') # 从请求体获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 参数"}), 400

        # 移除旧的从 process_api 获取 user_id 的逻辑

        plan = process_api.process_lang_direction(userId, lang, direction) # 传递从请求获取的 userId

        # 返回计划的JSON数据
        plan_data = plan.__dict__ if hasattr(plan, '__dict__') else plan
        return jsonify(plan_data), 200
    except ValueError as ve: # 捕获process_api中的特定错误
        return jsonify({"error": str(ve)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500

##固定步骤后执行
# 重命名并更新的接口
@app.route('/api/user/settings', methods=['POST'])
def set_user_settings():
    """保存用户的语言和方向设置""" # 更新 docstring
    try:
        data = request.json
        # level = data.get('level') # 不再需要 level
        lang = data.get('lang')
        direction = data.get('direction') # 始终使用'direction'

        # # 验证等级 # 不再需要 level 验证
        # if level is None or not isinstance(level, int) or level < 0: # 允许等级为0
        #      return jsonify({"error": "无效或缺失 'level' 值"}), 400
        # 验证语言
        if not lang or not isinstance(lang, str):
             return jsonify({"error": "无效或缺失 'lang' 值"}), 400
        # 方向可以为空或字符串
        if direction is None:
             direction = "" # 确保方向是字符串
        elif not isinstance(direction, str):
             return jsonify({"error": "无效的 'direction' 值"}), 400

        userId = data.get('userId') # 从请求体获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 参数"}), 400

        # 移除旧的从 process_api 获取 user_id 的逻辑

        process_api.save_user_settings(userId, lang, direction) # 传递从请求获取的 userId
        # 更新响应消息
        return jsonify({"message": f"用户设置已保存: lang={lang}, direction='{direction}'"}), 200
    except Exception as e:
        return jsonify({"error": str(e)}), 500

##起始步骤1
@app.route('/api/user/status', methods=['GET'])
def get_user_status_route():
    """获取用户状态（是否新用户，用户等级, 语言, 方向）"""
    try:
        userId = request.args.get('userId') # 从查询参数获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 查询参数"}), 400

        # 移除旧的从 process_api 获取 user_id 的逻辑

        user_status = process_api.get_user_status(userId) # 传递从请求获取的 userId
        return jsonify(user_status), 200
    except Exception as e:
        return jsonify({"error": str(e)}), 500

##迎新第二步
@app.route('/api/user/mark_not_new', methods=['POST'])
def mark_user_not_new_route():
    """将用户标记为非新用户"""
    try:
        data = request.json # 获取请求体
        userId = data.get('userId') # 从请求体获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 参数"}), 400

        # 移除旧的从 process_api 获取 user_id 的逻辑

        process_api.set_user_not_new(userId) # 传递从请求获取的 userId
        return jsonify({"message": "用户已标记为非新用户"}), 200
    except Exception as e:
        return jsonify({"error": str(e)}), 500

##老用户第二步
# New endpoint to get the user's plan data
@app.route('/api/plan', methods=['GET'])
def get_plan_route():
    """获取用户的计划数据 (plans, intro)"""
    try:
        userId = request.args.get('userId') # 从查询参数获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 查询参数"}), 400
        plan_data = process_api.get_plan_data(userId) # 传递从请求获取的 userId
        if plan_data:
            return jsonify(plan_data), 200
        else:
            # 计划文件可能不存在，基于当前用户设置
            return jsonify({"error": "无法根据当前用户设置找到或读取计划文件"}), 404
    except Exception as e:
        # 捕获文件读取或处理中的潜在错误
        return jsonify({"error": str(e)}), 500

##老用户第一步
@app.route('/api/plans/list', methods=['GET'])
def list_plans_route():
    """ 列出用户的所有可用计划（语言和方向） """
    try:
        userId = request.args.get('userId') # 从查询参数获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 查询参数"}), 400
        plans_list = process_api.list_user_plans(userId) # 传递从请求获取的 userId
        return jsonify(plans_list), 200
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route('/api/plan/level', methods=['POST'])
def set_plan_level_route():
    """更新当前计划的用户等级"""
    try:
        data = request.json
        new_level = data.get('level')

        # 验证 level
        if new_level is None or not isinstance(new_level, int) or new_level < 0:
            return jsonify({"error": "无效或缺失 'level' 值"}), 400

        userId = data.get('userId') # 从请求体获取 userId
        if not userId:
            return jsonify({"error": "缺少 'userId' 参数"}), 400

        # 获取当前的 lang 和 direction 以确定要更新哪个计划文件
        user_data = process_api.get_user_data(userId) # 使用从请求获取的 userId
        if not user_data: # 检查 get_user_data 是否返回有效数据
            return jsonify({"error": f"无法找到用户 '{userId}' 的数据"}), 404

        lang = user_data.get("lang")
        direction = user_data.get("direction")

        if not lang: # 方向可能为空，但需要语言
             return jsonify({"error": "当前用户未设置语言，无法更新计划等级"}), 400

        # 调用新的 process_api 函数保存 level 到计划文件
        success = process_api.save_plan_level(userId, lang, direction, new_level) # 使用从请求获取的 userId

        if success:
            return jsonify({"message": f"计划等级已更新为 {new_level}"}), 200
        else:
            # save_plan_level 内部会打印错误，这里返回通用错误
            return jsonify({"error": "更新计划等级失败"}), 500

    except Exception as e:
        return jsonify({"error": str(e)}), 500


    except Exception as e:
        return jsonify({"error": str(e)}), 500
@app.route('/api/login/login', methods=['POST'])
def login_route():
    """处理登录请求"""
    data = request.json
    userId = data.get('userId')
    password = data.get('password')
    success,errormsg=process_api.login(userId, password)
    if success:
        # 使用字典返回 JSON，并包含 userId
        return jsonify({"success": success, "message": "登录成功", "userId": userId}), 200
    else:
        # 使用字典返回 JSON
        return jsonify({"success": success, "message": errormsg}), 401
@app.route('/api/login/register', methods=['POST'])
def register_route():
    """处理注册请求"""
    data = request.json
    userId = data.get('userId')
    password = data.get('password')
    success,errormsg=process_api.register(userId, password)
    if success:
        # 使用 "message" 作为键，保持一致性
        return jsonify({"success": success, "message": "注册成功"}), 200
    else:
        # 使用 "message" 作为键，保持一致性
        return jsonify({"success": success, "message": errormsg}), 401

# 新增：项目列表路由
@app.route('/api/project/list', methods=['GET'])
def list_projects_route():
    """获取指定用户、语言、方向和步骤的项目列表"""
    try:
        user_id = request.args.get('userId')
        lang = request.args.get('lang')
        direction = request.args.get('direction')
        step_str = request.args.get('step')

        if not user_id:
            return jsonify({"error": "缺少 'userId' 查询参数"}), 400
        if not lang:
            return jsonify({"error": "缺少 'lang' 查询参数"}), 400
        if direction is None: # direction 可以是空字符串
             direction = ""
        if not step_str:
            return jsonify({"error": "缺少 'step' 查询参数"}), 400

        try:
            step = int(step_str)
        except ValueError:
            return jsonify({"error": "'step' 参数必须是整数"}), 400

        # 调用更新后的 get_project_list 函数
        projects = process_api.get_project_list_wrapper(user_id, lang, direction, step)
        return jsonify(projects), 200
    except Exception as e:
        # 尝试获取 userId 用于日志记录，如果失败则使用 'Unknown'
        user_id_for_log = request.args.get('userId', 'Unknown')
        print(f"Error fetching project list for user {user_id_for_log}: {e}") # 记录详细错误
        return jsonify({"error": f"获取项目列表时发生错误: {str(e)}"}), 500

# 新增：创建新项目
@app.route('/api/project/new', methods=['POST'])
def new_project_route():
    """根据用户当前的计划和等级生成一个新的项目"""
#   userId: string,
#   lang: string,
#   direction: string,
#   step: number, 解析的时候为level

    data = request.json
    user_id = data.get('userId')
    user_level_str = data.get('level') # 前端命名不同
    proj_name=data.get('proj_name')
    #这要传入是考虑到用户可能会在旧的plan下创建新的项目
    user_level=int(user_level_str)
    if not user_id:
        return jsonify({"error": "缺少 'userId' 参数"}), 400
    if user_level_str is None: # level 可以是 0
        return jsonify({"error": "缺少 'level' 参数"}), 400

    plan_data=process_api.get_plan_data(user_id)
    plan_data["user_level"]=user_level
    project_dict = process_api.new_project_wrapper(plan_data, user_level,proj_name)
    if project_dict:
        # 移除重命名逻辑，直接返回包含 'md' 的字典
        # if 'md' in project_dict:
        #     project_dict['project_md'] = project_dict.pop('md') # 将 'md' 重命名为 'project_md'
        return jsonify(project_dict), 200
    else:
        return jsonify({"error": "生成新项目失败，请稍后重试"}), 500
    

# 新增：获取项目内容
@app.route('/api/project/get', methods=['GET'])
def get_project_route():
    """获取特定项目的内容 (代码, README, 名称, 答案)"""
    try:
        user_id = request.args.get('userId')
        lang = request.args.get('lang')
        direction = request.args.get('direction')
        step_str = request.args.get('step')
        project_index_str = request.args.get('projectIndex') # 假设前端用 projectIndex

        # 参数校验
        if not user_id: return jsonify({"error": "缺少 'userId' 查询参数"}), 400
        if not lang: return jsonify({"error": "缺少 'lang' 查询参数"}), 400
        if direction is None: direction = ""
        if not step_str: return jsonify({"error": "缺少 'step' 查询参数"}), 400
        if not project_index_str: return jsonify({"error": "缺少 'projectIndex' 查询参数"}), 400

        try:
            step = int(step_str)
            project_index = int(project_index_str)
        except ValueError:
            return jsonify({"error": "'step' 和 'projectIndex' 必须是整数"}), 400

        # 调用包装函数
        project_dict = process_api.get_project_content_wrapper(user_id, lang, direction, step, project_index)

        if project_dict:
            return jsonify(project_dict), 200
        else:
            return jsonify({"error": "找不到指定的项目"}), 404

    except Exception as e:
        print(f"Error in /api/project/get: {e}") # 记录详细错误
        return jsonify({"error": f"获取项目内容时发生错误: {str(e)}"}), 500

#新建project的保存api,不需要传入index
@app.route('/api/project/save_new', methods=['POST'])
def save_new_project_route():
    #新建project的保存
    try:
        data = request.json
        user_id = data.get('userId')
        lang = data.get('lang')
        direction = data.get('direction')
        step_str = data.get('step')
        project_data_dict = data.get('projectData') # 假设前端发送 projectData

        # 参数校验
        if not user_id: return jsonify({"error": "缺少 'userId' 参数"}), 400
        if not lang: return jsonify({"error": "缺少 'lang' 参数"}), 400
        if direction is None: direction = ""
        if step_str is None: return jsonify({"error": "缺少 'step' 参数"}), 400
        if not project_data_dict: return jsonify({"error": "缺少 'projectData' 参数"}), 400


        step = int(step_str)


        # 直接使用字典数据
        try:
            project_data = project_data_dict
        except KeyError as e:
            return jsonify({"error": f"'projectData' 缺少键: {e}"}), 400

        # 调用 project.py 中的 save_project 函数
        # 调用更新后的包装函数，不再传递 project_index
        process_api.save_new_project_wrapper(user_id, lang, direction, step, project_data)

        # 返回通用成功消息，因为 project_index 在后端确定
        return jsonify({"message": f"项目已成功保存"}), 200

    except Exception as e:
        print(f"Error in /api/project/save: {e}") # 记录详细错误
        return jsonify({"error": f"保存项目时发生错误: {str(e)}"}), 500

@app.route('/api/project/save', methods=['POST'])
def save_project_route(): # <-- Renamed function
    """保存用户对特定项目的修改"""
    try:
        data = request.json
        user_id = data.get('userId')
        lang = data.get('lang')
        direction = data.get('direction')
        step_str = data.get('step')
        project_index_str = data.get('projectIndex')
        project_data_dict = data.get('projectData') # 假设前端发送 projectData

        # 参数校验
        if not user_id: return jsonify({"error": "缺少 'userId' 参数"}), 400
        if not lang: return jsonify({"error": "缺少 'lang' 参数"}), 400
        if direction is None: direction = ""
        if step_str is None: return jsonify({"error": "缺少 'step' 参数"}), 400
        if project_index_str is None: return jsonify({"error": "缺少 'projectIndex' 参数"}), 400
        if not project_data_dict: return jsonify({"error": "缺少 'projectData' 参数"}), 400

        step = int(step_str)
        project_index = int(project_index_str) 

        # 直接使用字典数据
        try:
            project_data = project_data_dict
        except KeyError as e:
            return jsonify({"error": f"'projectData' 缺少键: {e}"}), 400

        # 调用 project.py 中的 save_project 函数
        # 调用更新后的包装函数，不再传递 project_index
        process_api.save_project_wrapper(user_id, lang, direction, step, project_data,project_index)

        # 返回通用成功消息，因为 project_index 在后端确定
        return jsonify({"message": f"项目已成功保存"}), 200

    except Exception as e:
        print(f"Error in /api/project/save: {e}") # 记录详细错误
        return jsonify({"error": f"保存项目时发生错误: {str(e)}"}), 500



# --- 新增 API：执行代码并测试 --- 
@app.route('/api/exec', methods=['POST'])
def exec_code_route():
    """执行用户代码并使用生成的测试用例进行测试"""
    try:
        data = request.json
        user_id = data.get('userId')
        lang = data.get('lang')
        direction = data.get('direction')
        step_str = data.get('step')
        project_index_str = data.get('projectIndex')
        user_code = data.get('userCode') # 假设前端发送 userCode

        # 参数校验
        if not user_id: return jsonify({"error": "缺少 'userId' 参数"}), 400
        if not lang: return jsonify({"error": "缺少 'lang' 参数"}), 400
        if direction is None: direction = ""
        if not step_str: return jsonify({"error": "缺少 'step' 参数"}), 400
#     if not project_index_str: return jsonify({"error": "缺少 'projectIndex' 参数"}), 400  有可能等于0
        if user_code is None: return jsonify({"error": "缺少 'userCode' 参数"}), 400

        try:
            step = int(step_str)
            project_index = int(project_index_str)
        except ValueError:
            return jsonify({"error": "'step' 和 'projectIndex' 必须是整数"}), 400

        # 调用 process_api 中的执行逻辑
        result = process_api.process_exec_api(user_id, lang, direction, step, project_index, user_code)
        return jsonify(result), 200

    except ValueError as ve:
        # 捕获 process_api 中可能抛出的 ValueError (例如找不到项目或无法生成测试用例)
        return jsonify({"error": str(ve)}), 400
    except Exception as e:
        print(f"Error in /api/exec: {e}") # 记录详细错误
        return jsonify({"error": f"执行代码时发生错误: {str(e)}"}), 500

# --- 新增 API：评估代码 --- 
@app.route('/api/evaluate', methods=['POST'])
def evaluate_code_route():
    """根据测试结果评估用户代码"""
    try:
        data = request.json
        user_id = data.get('userId')
        lang = data.get('lang')
        direction = data.get('direction')
        step_str = data.get('step')
        project_index_str = data.get('projectIndex')
        result_dict = data.get('testResults') # 前端发送包含测试结果的字典
        user_code = data.get('userCode')      

        # 参数校验
        if not user_id: return jsonify({"error": "缺少 'userId' 参数"}), 400
        if not lang: return jsonify({"error": "缺少 'lang' 参数"}), 400
        if direction is None: direction = ""
        if not step_str: return jsonify({"error": "缺少 'step' 参数"}), 400
#     if not project_index_str: return jsonify({"error": "缺少 'projectIndex' 参数"}), 400  有可能等于0
        if result_dict is None: return jsonify({"error": "缺少 'testResults' 参数"}), 400
        if user_code is None: return jsonify({"error": "缺少 'userCode' 参数"}), 400

        try:
            step = int(step_str)
            project_index = int(project_index_str)
        except ValueError:
            return jsonify({"error": "'step' 和 'projectIndex' 必须是整数"}), 400

        # 调用 process_api 中的评估逻辑
        evaluation = process_api.process_evaluate_api(user_id, lang, direction, step, project_index, result_dict, user_code)
        return jsonify({"evaluation": evaluation}), 200

    except ValueError as ve:
        # 捕获 process_api 中可能抛出的 ValueError (例如找不到项目)
        return jsonify({"error": str(ve)}), 400
    except Exception as e:
        print(f"Error in /api/evaluate: {e}") # 记录详细错误
        return jsonify({"error": f"评估代码时发生错误: {str(e)}"}), 500


if __name__ == "__main__":
    # 确保计划目录存在（尽管process_api也会执行此操作）
    os.makedirs(process_api.PLANS_DIR, exist_ok=True)
    os.makedirs(process_api.USER_DATA_DIR, exist_ok=True)
    # 确保项目基础目录存在
    if not os.path.exists(process_api.PROJECT_BASE_DIR):
        os.makedirs(process_api.PROJECT_BASE_DIR, exist_ok=True)
    app.run(debug=True, port=5000)
